package com.alibaba.algo.domain.user;

import com.alibaba.algo.core.base.BaseDomain;
import com.alibaba.algo.dao.user.SysUserCacheMapper;
import com.alibaba.algo.entity.user.SysUser;
import com.alibaba.algo.entity.user.SysUserCache;
import com.alibaba.algo.enums.SysUserCacheStatusEnum;
import com.alibaba.algo.utils.CacheUtil;
import com.alibaba.algo.utils.JedisUtil;
import com.alibaba.algo.utils.ThreadPoolUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Component
@Slf4j
public class SysUserCacheDomain extends BaseDomain<SysUserCache> {

    @Autowired
    private SysUserCacheMapper sysUserCacheMapper;

    private void batchInsert(List<String> keys) {
        if (CollectionUtils.isEmpty(keys)) {
            log.info("batchInsert keys is empty");
            return;
        }

        List<SysUserCache> sysUserCacheList = new ArrayList<>();
        for (String key : keys) {
            if (StringUtils.isEmpty(key)) {
                continue;
            }
            SysUserCache sysUserCache = new SysUserCache();
            sysUserCache.setCacheKey(key);
            sysUserCache.setStatus(SysUserCacheStatusEnum.INIT.getValue());
            sysUserCache.setGmtCreated(LocalDateTime.now());
            sysUserCache.setGmtModified(sysUserCache.getGmtCreated());
            sysUserCacheList.add(sysUserCache);
        }
        sysUserCacheMapper.batchInsert(sysUserCacheList);
    }

    public int updateByIdAndStatus(SysUserCache entity) {
        return sysUserCacheMapper.updateByIdAndStatus(entity);
    }

    /**
     * 构建Redis Key清单
     */
    private void buildUserRedisKeyList(SysUser oriUser, List<String> redisKeyList, Set<String> dataTypeSet) {
        if (null == oriUser) {
            log.info("buildUserRedisKeyList sysUser is null");
            return;
        }

        if (CollectionUtils.isEmpty(dataTypeSet)) {
            dataTypeSet = new HashSet<>();
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_ID_MAP_EMP);
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_ID_MAP_ACT);
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_INFO_USER);
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_INFO_EMPLOYEE);
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_INFO_ORG);
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_INFO_POSITION);
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_INFO_ROLE);
            dataTypeSet.add(CacheUtil.REDIS_KEY_USER_INFO_GROUP);
        }

        if (!ObjectUtils.isEmpty(oriUser.getEmployeeCode())
                && dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_ID_MAP_EMP)) {
            String empRedisKey = CacheUtil.getUserIdMapEmpKey(oriUser.getEmployeeCode());
            redisKeyList.add(empRedisKey);
        }

        if (!ObjectUtils.isEmpty(oriUser.getUserAccount())
                && dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_ID_MAP_ACT)) {
            String actRedisKey = CacheUtil.getUserIdMapActKey(oriUser.getUserAccount());
            redisKeyList.add(actRedisKey);
        }

        if (null != oriUser.getId() && oriUser.getId() > 0) {
            if (dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_INFO_USER)) {
                redisKeyList.add(CacheUtil.getUserInfoUserKey(oriUser.getId()));
            }
            if (dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_INFO_EMPLOYEE)) {
                redisKeyList.add(CacheUtil.getUserInfoEmployeeKey(oriUser.getId()));
            }
            if (dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_INFO_ORG)) {
                redisKeyList.add(CacheUtil.getUserInfoOrgKey(oriUser.getId()));
            }
            if (dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_INFO_POSITION)) {
                redisKeyList.add(CacheUtil.getUserInfoPositionKey(oriUser.getId()));
            }
            if (dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_INFO_ROLE)) {
                redisKeyList.add(CacheUtil.getUserInfoRoleKey(oriUser.getId()));
            }
            if (dataTypeSet.contains(CacheUtil.REDIS_KEY_USER_INFO_GROUP)) {
                redisKeyList.add(CacheUtil.getUserInfoGroupKey(oriUser.getId()));
            }
        }
    }

    /**
     * 批量删除缓存的用户信息--指定类型
     */
    public void batchDeleteUserInfoFromCache(List<SysUser> oriUserList, Set<String> dataTypeSet) {
        if (null == oriUserList || oriUserList.size() <= 0) {
            log.info("batchDeleteUserInfoFromCache oriUserList is null");
            return;
        }

        try {
            List<String> keys = new ArrayList<>();
            oriUserList.forEach(item -> {
                buildUserRedisKeyList(item, keys, dataTypeSet);
            });

            if (CollectionUtils.isEmpty(keys)) {
                log.info("batchDeleteUserInfoFromCache redisKeyList is empty");
                return;
            }

            // 执行删除
            ThreadPoolUtil.getThreadPool().submit(() -> {
                //1、执行首次删除
                Map<String, Long> resultMap = JedisUtil.batchDel(keys);
                log.info("batchDeleteUserInfoFromCache1 keys:{},result:{}", JSON.toJSONString(keys), JSON.toJSONString(resultMap));

                //2、避免因删除瞬间被再次放入，需要做延时二次删除
                try {
                    Thread.sleep(CacheUtil.DELAY_MILLIS);//延迟5秒
                } catch (InterruptedException ex) {
                    log.error("batchDeleteUserInfoFromCache Thread.sleep exeption", ex);
                }
                resultMap = JedisUtil.batchDel(keys);
                log.info("batchDeleteUserInfoFromCache2 keys:{},result:{}", JSON.toJSONString(keys), JSON.toJSONString(resultMap));

                //3、删除失败的情况增加异常处理
                List<String> delFailKeys = CacheUtil.getDelFailKeys(resultMap, keys);
                if (!CollectionUtils.isEmpty(delFailKeys)) {
                    log.info("batchDeleteUserInfoFromCache has failed,keys:{}", JSON.toJSONString(delFailKeys));
                    batchInsert(delFailKeys);
                }
            });
        } catch (Exception ex) {
            log.error("batchDeleteUserInfoFromCache 异常", ex);
        }
    }

    /**
     * 批量删除缓存的用户信息--全部类型
     */
    public void batchDeleteUserInfoFromCache(List<SysUser> oriUserList) {
        batchDeleteUserInfoFromCache(oriUserList, null);
    }
}
